package cn.iocoder.yudao.module.member.service.profit;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.member.controller.admin.profit.vo.ProfitMainSaveReqVO;
import cn.iocoder.yudao.module.member.controller.admin.profit.vo.ProfitPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.profit.vo.ProfitSaveReqVO;
import cn.iocoder.yudao.module.member.dal.dataobject.profit.ProfitDO;
import cn.iocoder.yudao.module.member.dal.mysql.profit.ProfitMapper;
import cn.iocoder.yudao.module.member.enums.profit.ProfitBizTypeEnum;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.PROFIT_TYPE_ON;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.USER_CERTIFICATE_ORDER_NOT_RETURN;

@Slf4j
@Service
@Validated
public class ProfitServiceImpl implements ProfitService {

    @Resource
    private ProfitMapper profitMapper;
    @Resource
    private ProfitMainService profitMainService;

    /**
     * 创建系统利润明细
     *
     * @param createReqVO 创建信息
     * @return 编号
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createProfit(ProfitSaveReqVO createReqVO) {
        ProfitBizTypeEnum byType = ProfitBizTypeEnum.getByType(createReqVO.getType());
        // 插入
        ProfitDO profit = BeanUtils.toBean(createReqVO, ProfitDO.class);
        profit.setDescription( StrUtil.format(byType.getDescription(), createReqVO.getPrice(), createReqVO.getCostPrice(), createReqVO.getProfit()));
        profitMapper.insert(profit);
        // 返回
        return profit.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void excuteSignTask() throws Exception {
        Date startDate = new Date();
        log.info("开始统计"+ DateUtil.offsetDay(startDate,-1) +"的利润");
        Long number = this.profitMapper.countTotal(DateUtil.format(DateUtil.offsetDay(startDate,-1), DatePattern.NORM_DATE_FORMAT) );

        List<ProfitDO> records = new ArrayList<>();
        if (number > 2000) {
            //一次性查询2000条记录
            ProfitPageReqVO preqVO = new ProfitPageReqVO();
            preqVO.setPageNo(1);
            preqVO.setPageSize(2000);
            preqVO.setCreateTime(DateUtil.format(DateUtil.offsetDay(startDate,-1), DatePattern.NORM_DATE_FORMAT));
            PageResult<ProfitDO> profitDOPageResult = this.profitMapper.selectPage(preqVO);
            if (ObjectUtils.isNotEmpty(profitDOPageResult) && !CollectionUtils.isEmpty(profitDOPageResult.getList())) {
                records.addAll(profitDOPageResult.getList());
            }
        } else {
            Long i = number / 2000;
            Long k = number % 2000;
            if (k != 0) {
                i = i + 1;
            }
            for (int j = 1; j < i+1; j++) {
                ProfitPageReqVO preqVO = new ProfitPageReqVO();
                preqVO.setPageNo(j);
                preqVO.setPageSize(2000);
                preqVO.setCreateTime(DateUtil.format(DateUtil.offsetDay(startDate,-1), DatePattern.NORM_DATE_FORMAT));
                PageResult<ProfitDO> profitDOPageResult  = this.profitMapper.selectPage(preqVO);
                if (ObjectUtils.isNotEmpty(profitDOPageResult) && !CollectionUtils.isEmpty(profitDOPageResult.getList())) {
                    records.addAll(profitDOPageResult.getList());
                }
            }
        }

        if (CollectionUtils.isEmpty(records)){
            log.info("未查到利润");
            return;
        }
        //按类型分组
        Map<Integer, List<ProfitDO>> collect = records.stream().collect(Collectors.groupingBy(ProfitDO::getType));

        ProfitMainSaveReqVO profitMainSaveReqVO = new ProfitMainSaveReqVO();

         BigDecimal totalProfit = BigDecimal.ZERO;

         BigDecimal totalCost = BigDecimal.ZERO;

         BigDecimal totalSales = BigDecimal.ZERO;
        collect.forEach((type, profitDOS) -> {
            ProfitBizTypeEnum byType = ProfitBizTypeEnum.getByType(type);
            if (byType == null){
                throw exception(PROFIT_TYPE_ON);
            }
            /**
             * 默认 P8 P12 都是统计到私有价格
             */
            if(byType==ProfitBizTypeEnum.ADD_UP_LOAD){
                 BigDecimal privatePoolCost = profitMainSaveReqVO.getPrivatePoolCost();
                 BigDecimal privatePoolSales = profitMainSaveReqVO.getPrivatePoolSales();
                for (ProfitDO profitDO : profitDOS) {
                    privatePoolCost =   privatePoolCost.add(profitDO.getCostPrice());
                    privatePoolSales =   privatePoolSales.add(profitDO.getPrice());
                }
                profitMainSaveReqVO.setPrivatePoolCost(privatePoolCost);
                profitMainSaveReqVO.setPrivatePoolSales(privatePoolSales);

            }

            if(byType==ProfitBizTypeEnum.ADD_UP_LOAD_PRIVATE){
                BigDecimal privatePoolCost = profitMainSaveReqVO.getPrivatePoolCost();
                BigDecimal privatePoolSales = profitMainSaveReqVO.getPrivatePoolSales();
                for (ProfitDO profitDO : profitDOS) {
                    privatePoolCost =   privatePoolCost.add(profitDO.getCostPrice());
                    privatePoolSales =   privatePoolSales.add(profitDO.getPrice());
                }
                profitMainSaveReqVO.setPrivatePoolCost(privatePoolCost);
                profitMainSaveReqVO.setPrivatePoolSales(privatePoolSales);

            }

            if(byType==ProfitBizTypeEnum.ADD_CERTIFICATE_ORDER){
                BigDecimal certificateCost = new BigDecimal(0);
                BigDecimal certificateSales = new BigDecimal(0);
                for (ProfitDO profitDO : profitDOS) {
                    certificateCost =   certificateCost.add(profitDO.getCostPrice());
                    certificateSales =   certificateSales.add(profitDO.getPrice());
                }
                profitMainSaveReqVO.setCertificateCost(certificateCost);
                profitMainSaveReqVO.setCertificateSales(certificateSales);
            }

            if(byType==ProfitBizTypeEnum.ADD_DEVICE_ORDER){
                BigDecimal deviceCost = new BigDecimal(0);
                BigDecimal deviceCostSales = new BigDecimal(0);
                for (ProfitDO profitDO : profitDOS) {
                    deviceCost =   deviceCost.add(profitDO.getCostPrice());
                    deviceCostSales =   deviceCostSales.add(profitDO.getPrice());
                }
                profitMainSaveReqVO.setDeviceCost(deviceCost);
                profitMainSaveReqVO.setDeviceSales(deviceCostSales);
            }
            profitMainSaveReqVO.setProfitTime(DateUtil.offsetDay(startDate,-1));
        });
        totalSales =profitMainSaveReqVO.getCertificateSales().add(profitMainSaveReqVO.getDeviceSales()).add(profitMainSaveReqVO.getPrivatePoolSales());
        totalCost = profitMainSaveReqVO.getCertificateCost().add(profitMainSaveReqVO.getDeviceCost()).add(profitMainSaveReqVO.getPrivatePoolCost());
        totalProfit = totalSales.subtract(totalCost);
        profitMainSaveReqVO.setTotalProfit(totalProfit);
        profitMainSaveReqVO.setTotalSales(totalSales);
        profitMainSaveReqVO.setTotalCost(totalCost);
        //计算利润
        profitMainService.createProfitMain(profitMainSaveReqVO);

    }
}
